home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / xmanager.pro < prev    next >
Text File  |  1997-07-08  |  26KB  |  708 lines

  1. ; $Id: xmanager.pro,v 1.39 1997/03/04 17:19:54 lubos Exp $
  2. ;
  3. ; Copyright (c) 1991-1997, Research Systems, Inc.  All rights reserved.
  4. ;    Unauthorized reproduction prohibited.
  5.  
  6. ;+
  7. ; NAME:
  8. ;    XMANAGER
  9. ;
  10. ; PURPOSE:
  11. ;    Provide management for widgets client applications created using IDL.
  12. ;
  13. ; CATEGORY:
  14. ;    Widgets.
  15. ;
  16. ; CALLING SEQUENCE:
  17. ;    XMANAGER [, Name, ID]
  18. ;
  19. ; OPTIONAL INPUTS:
  20. ;    NAME:    A string giving the name of the application that is being
  21. ;        registered.
  22. ;  
  23. ;    ID:    The widget ID of the top level base of the new client.
  24. ;
  25. ; KEYWORD PARAMETERS:
  26. ;    BACKGROUND:
  27. ;        -------------------------------------------------------------
  28. ;        | PLEASE NOTE: This keyword is OBSOLETE. It's functionality |
  29. ;        | is provided by the TIMER keyword to the WIDGET_CONTROL    |
  30. ;        | procedure.                                                |
  31. ;        -------------------------------------------------------------
  32. ;
  33. ;    CATCH: If TRUE, tells XMANAGER to use CATCH when dispatching
  34. ;        widget events. If FALSE, CATCH is not used and execution
  35. ;        halts on error. The default is TRUE. If CATCH is specified,
  36. ;        the internal state of XMANAGER is updated and it returns
  37. ;        immediately without taking any further action. CATCH
  38. ;        is only effective if XMANAGER is blocking to dispatch
  39. ;        errors. If active command line event dispatching is in
  40. ;        use, it has no effect.
  41. ;
  42. ;    CLEANUP: This keyword contains a string that is the name of the
  43. ;        routine called when the widget dies.  If not specified,
  44. ;        no routine is called.  The cleanup routine must accept one 
  45. ;        parameter which is the widget id of the dying widget. This
  46. ;        routine is set as the KILL_NOTIFY routine for the widget.
  47. ;
  48. ;    EVENT_HANDLER: The name of the event handling routine that is to be
  49. ;        called when a widget event occurs in the registered
  50. ;        application. If this keyword is not supplied, the Xmanager
  51. ;        will construct a default name by adding the "_EVENT" suffix
  52. ;        to the NAME argument. See below for a more detailed
  53. ;        explanation.
  54. ;
  55. ;    GROUP_LEADER: The widget id of the group leader for the application
  56. ;        being registered.  When the leader dies, all widgets that have
  57. ;        that leader will also die.
  58. ;
  59. ;        For example, a widget that views a help file for a demo 
  60. ;        widget would have that demo widget as it's leader.  When
  61. ;        the help widget is registered, it sets the keyword 
  62. ;        GROUP_LEADER to the widget id of the demo widget. If 
  63. ;        the demo widget is destroyed, the help widget led by 
  64. ;        the it would be killed by the XMANAGER.
  65. ;
  66. ;    JUST_REG:    
  67. ;        This keyword tells the manager to just register the widget
  68. ;        but not to start doing the event processing.  This is useful
  69. ;        when you want to register a group of related top level widgets
  70. ;        but need to regain control immediately afterwards.
  71. ;
  72. ;        NOTE: JUST_REG does not do the same thing as NO_BLOCK. This is
  73. ;        explained in detail below under "SIDE EFFECTS".
  74. ;
  75. ;     MODAL:
  76. ;        --------------------------------------------------------------
  77. ;        | PLEASE NOTE: This keyword is OBSOLETE. It's functionality  |
  78. ;        | is provided by the MODAL keyword to the WIDGET_BASE        |
  79. ;        | procedure.                                                 |
  80. ;        --------------------------------------------------------------
  81. ;
  82. ;        When this keyword is set, the widget that is being registered
  83. ;        traps all events and desensitizes all the other widgets.  It
  84. ;        is useful when input from the user is necessary before
  85. ;        continuing. Once the modal widget dies, the others are
  86. ;        resensitized and the normal event processing is restored.
  87. ;        XMANAGER is therefore using sensitivity to provide the
  88. ;        illusion of modality. The WIDGET_BASE keyword is a newer
  89. ;        IDL feature that provides the real thing.
  90. ;
  91. ;    NO_BLOCK: If set, tells XMANAGER that the registering client
  92. ;        does not require XMANAGER to block if active command line
  93. ;        event processing is available. If active command line
  94. ;        event processing is available *AND* every current XMANAGER
  95. ;        client specifies NO_BLOCK, then XMANAGER will not block
  96. ;        and the user will have access to the command line while
  97. ;        widget applications are running.
  98. ;
  99. ;        NOTE: NO_BLOCK does not do the same thing as JUST_REG. This is
  100. ;        explained in detail below under "SIDE EFFECTS".
  101. ;
  102. ; OUTPUTS:
  103. ;    No outputs.
  104. ;
  105. ; COMMON BLOCKS:
  106. ;    MANAGED
  107. ;    XMANAGER_LOCAL:
  108. ;        Common blocks used for module state maintenance. These common
  109. ;        blocks are considered private to this module and should not
  110. ;        be referenced outside RSI supplied routines. They are
  111. ;        subject to change without notice.
  112. ;    
  113. ;
  114. ; SIDE EFFECTS:
  115. ;
  116. ;    JUST_REG vs NO_BLOCK
  117. ;    --------------------
  118. ;       Although their names imply a similar function, the JUST_REG and
  119. ;    NO_BLOCK keywords perform very different services. It is important
  120. ;    to understand what they do and how they differ.
  121. ;
  122. ;       JUST_REG tells XMANAGER that it should simply register a client
  123. ;    and then return immediately. The result is that the client becomes
  124. ;    known to XMANAGER, and that future calls to XMANAGER will take this
  125. ;    client into account. Therefore, JUST_REG only controls how the
  126. ;    registering call to XMANAGER should behave. The registered client
  127. ;    can still be registered as requiring XMANAGER to block by not setting
  128. ;    NO_BLOCK. In this case, future calls to XMANAGER will block.
  129. ;
  130. ;    NO_BLOCK tells XMANAGER that the registered client does not
  131. ;    require XMANAGER to block if the command processing front end
  132. ;    is able to support active command line event processing (described
  133. ;    below). XMANAGER remembers this attribute of the client until
  134. ;    the client exits, even after the call to XMANAGER that registered the
  135. ;    client returns. NO_BLOCK is just a "vote" on how XMANAGER should
  136. ;    behave. The final decision is made by XMANAGER by considering the
  137. ;    NO_BLOCK attributes of all of its current clients as well as the
  138. ;    ability of the command front end in use to support the active command
  139. ;    line.
  140. ;
  141. ;    Blocking vs Non-blocking
  142. ;    ------------------------
  143. ;    The issue of blocking in XMANAGER requires some explanation.
  144. ;    IDL places incoming widget events into a queue of pending events.
  145. ;    The only way to get these events processed and dispatched is to
  146. ;    call the WIDGET_EVENT function. Arranging for WIDGET_EVENT to be
  147. ;    called properly is the primary job of XMANAGER. XMANAGER offers
  148. ;    two different modes of operation:
  149. ;
  150. ;        - The first (outermost) XMANAGER processes events by calling
  151. ;          WIDGET_EVENT as necessary until no managed clients remain on
  152. ;          the screen. This is referred to as "blocking", because XMANAGER
  153. ;          does not return to the caller until it is done, and the IDL
  154. ;          command line is not available.
  155. ;
  156. ;        - XMANAGER does not block, and instead, the part of IDL
  157. ;          that reads command input also watches for widget events
  158. ;          and calls WIDGET_EVENT as necessary while also reading
  159. ;          command input. This is referred to as "non-blocking" or
  160. ;          "active command line" mode.
  161. ;
  162. ;    The default is to block. However, if every currently active
  163. ;    application specified the NO_BLOCK keyword to XMANAGER, non-blocking
  164. ;    mode is used, if possible.
  165. ;
  166. ;    There are currently 5 separate IDL command input front end
  167. ;    implementations:
  168. ;
  169. ;        - Apple Macintosh IDE
  170. ;        - Microsoft Windows IDE
  171. ;        - Motif IDE (Unix and VMS)
  172. ;        - Unix plain tty
  173. ;        - VMS plain tty
  174. ;
  175. ;    Except for the VMS plain tty, all of these front ends are able to
  176. ;    support the non-blocking active command line. VMS users can have
  177. ;    an active command line by using the IDLde interface. The decision
  178. ;    on whether XMANAGER blocks to process widget events is determined
  179. ;    by the following rules, in order of precedence:
  180. ;
  181. ;        - Use of the MODAL keyword will cause XMANAGER to block.
  182. ;        - Setting JUST_REG to 1 ensures that XMANAGER will not block.
  183. ;        - If using the VMS plain tty interface, XMANAGER will block.
  184. ;        - If none of the previous rules apply, XMANAGER will block
  185. ;          if any of its currently active clients were registered without
  186. ;          specifying NO_BLOCK. If NO_BLOCK is specified for every client,
  187. ;          XMANAGER will not block and will instead return and allow
  188. ;          active command line processing to take place.
  189. ;
  190. ;    When possible, applications should set the NO_BLOCK keyword.
  191. ;    This allows the IDL command line to be active while events are
  192. ;    being processed, which is highly desirable.
  193. ;
  194. ;
  195. ; RESTRICTIONS:
  196. ;    The implementation of XMANAGER may change in the future. Details
  197. ;    of its internal implementation must not be relied upon --- only
  198. ;    its external definition can be considered stable.
  199. ;
  200. ;    XMANAGER uses several undocumented features provided by the
  201. ;    internal WIDGET routines. These features are private to RSI, and
  202. ;    are not guaranteed to remain in IDL or to remain unchanged. They
  203. ;    exist only to support XMANAGER and should not be used elsewhere:
  204. ;
  205. ;        WIDGET_CONTROL, /XMANAGER_ACTIVE_COMMAND
  206. ;        WIDGET_EVENT,   /BREAK_ON_EXPOSE
  207. ;        WIDGET_EVENT,   /EVENT_BREAK
  208. ;        WIDGET_EVENT,   /XMANAGER_BLOCK
  209. ;        WIDGET_INFO,    /XMANAGER_BLOCK
  210. ;
  211. ;    These features are undocumented because they are not considered
  212. ;    permanent. Research Systems reserves the right to remove or alter
  213. ;    these features at any time.
  214. ;
  215. ; EXAMPLE USE:
  216. ;    To create a widget named Example that is just a base widget with a done
  217. ;    button using the XMANAGER you would do the following:
  218. ;
  219. ;
  220. ;    ;------ first - the event handler routine ------;
  221. ;
  222. ;     PRO example_event, ev            ;this is the routine that 
  223. ;                        ;deals with the events in the 
  224. ;                        ;example widget.
  225. ;    
  226. ;    WIDGET_CONTROL, ev.id, GET_UVALUE = uv    ;the uservalue is retrieved 
  227. ;                        ;from the widget where the 
  228. ;                        ;event occurred
  229. ;
  230. ;    if(uv eq 'DONE') then $            ;if the event occurred in the
  231. ;      WIDGET_CONTROL, ev.top, /DESTROY    ;done button then kill the 
  232. ;     END                    ;widget example
  233. ;
  234. ;
  235. ;    ;------ second - the main routine ------;
  236. ;
  237. ;     PRO example                ;this is the main routine
  238. ;                        ;that builds the widget and
  239. ;                        ;registers it with the Xmanager
  240. ;    
  241. ;    base = WIDGET_BASE(TITLE = 'Example')    ;first the base is created
  242. ;    
  243. ;    done = WIDGET_BUTTON(base, $        ;next the done button is 
  244. ;                 TITLE = 'DONE', $    ;created and it's user value
  245. ;                 UVALUE = 'DONE')    ;set to "DONE"
  246. ;
  247. ;    WIDGET_CONTROL, base, /REALIZE        ;the widget is realized
  248. ;
  249. ;    XManager, 'example', base        ;finally the example widget
  250. ;                        ;is registered with the 
  251. ;                        ;Xmanager
  252. ;     END
  253. ;
  254. ;    notes:    First the event handler routine is listed.  The handler
  255. ;        routine has the same name as the main routine with the 
  256. ;        characters "_event" added.  If you would like to use another
  257. ;        event handler name, you would need to pass it's name in as
  258. ;        a string to the EVENT_HANDLER keyword.  Also notice that the
  259. ;        event routine is listed before the main routine.  This is 
  260. ;        because the compiler will not compile the event routine if
  261. ;        it was below the main routine.  This is only needed if both
  262. ;        routines reside in the same file and the file name is the same
  263. ;        as the main routine name with the ".pro" extension added.
  264. ;
  265. ;
  266. ; PROCEDURE:
  267. ;    When the first widget is registered, initialize the lists and then 
  268. ;    start processing events.  Continue registering widgets and dispatching
  269. ;    events until all the widgets have been destroyed.  When a widget is 
  270. ;    killed, destroy all widgets that list the destroyed widget as their 
  271. ;    leader, if any.
  272. ;
  273. ; RELATED FUNCTIONS AND PROCEDURES:
  274. ;    XREGISTERED, XMTOOL
  275. ;
  276. ; MODIFICATION HISTORY: Written by Steve Richards, November, 1990
  277. ;    SMR, Mar,  1991    Added a cleanup routine keyword to allow dying
  278. ;        widgets to clean themselves up when dying.
  279. ;    SMR, May,  1991 Fixed a bug found by Diane Parchomchuk where an error
  280. ;        occurred when registering a widget  ight after destroying another.
  281. ;    SMR & ACY, July, 1991
  282. ;        Fixed a bug found by Debra Wolkovitch where lone widgets being
  283. ;        destroyed and new ones created caused problems.
  284. ;    SMR, Sept, 1991    Changed cleanup to use the new WIDGET_INFO routine.
  285. ;    SMR & ACY, Oct,  1991
  286. ;        Fixed a bug where a background event that unregistered itself
  287. ;        after a time would result in an XMANAGER error.
  288. ;     SMR, Mar.  1992    Changed XMANAGER to use enhanced widget functions for
  289. ;        event processing.
  290. ;    SMR, Nov.  1992 Changed modal widget handling allowing nesting of
  291. ;        modal widgets.  The first modal desensitizes all current widgets
  292. ;        and subsequent modals only desensitize the modal that called them.
  293. ;    JIY, Apr.  1993 Changed modal widget handling process to not run the
  294. ;        event loop for nested modal widgets. Allowed for multiple modal
  295. ;        widgets.
  296. ;    AB & SMR, 17 November 1993
  297. ;        Added ID validity checking to desensitizing of modal widgets to
  298. ;        fix a bug where already dead widgets were being accessed.
  299. ;    DJE, Feb, 1995
  300. ;        Made it so that non-modal widgets created from a modal widget have
  301. ;        events processed in the modal widget's event loop. This fixes a
  302. ;        bug where xmanager wouldn't return immediately if there was a
  303. ;        modal widget somewhere in the nesting, even though a non-modal
  304. ;        widget was being added. The nesting level could get _very_ deep.
  305. ;    DJE, Apr 1995
  306. ;        Pass a local variable to WIDGET_EVENT in the MODAL case, instead
  307. ;        of passing the common block variable modalList. This avoids a bug
  308. ;        where modalList gets changed behind WIDGET_EVENT's back.
  309. ;    DJE, Apr 1996
  310. ;        Changes for handling asynchronous widget event dispatching.
  311. ;        Complete rewrite. Background tasks are no longer supported. The
  312. ;        MODAL keyword is now obsolete. Added CATCH and BLOCK keywords.
  313. ;    AB, May 1996
  314. ;        Made changes so that XMANAGER always blocks under VMS with the
  315. ;        non-GUI interface. This is due to the fact that the SMG$ system
  316. ;        routines used by IDL in the plain tty case cannot support
  317. ;        interleaving of X events with tty input.
  318. ;    AB, 9 January 1997
  319. ;        Changed the meaning of the CATCH keyword so that catching is the
  320. ;        default. Removed BLOCK and replaced with NO_BLOCK. Switched
  321. ;        default action back to blocking from unblocking based on feedback
  322. ;        from the IDL 5 beta. Added the ability to block only as long as a
  323. ;        client without NO_BLOCK is running, and then revert to the active
  324. ;        command line.
  325. ;    AB, 10 February 1997
  326. ;        Cleaned up code to make it easier to understand and maintain.
  327. ;        Also cleaned up the distinction between real modality (MODAL
  328. ;        keyword to WIDGET_BASE) and XMANAGER's older fake modality
  329. ;        (MODAL keyword to XMANAGER), and fixed bugs in the current
  330. ;        implementation of fake modality.
  331. ;-
  332.  
  333.  
  334.  
  335. PRO XmanagerPrintError
  336.   ; Called when a client error is caught to print the error out for
  337.   ; the user. Unfortunately no stack trace is available, but that's
  338.   ; why XMANAGER,CATCH=0 exists.
  339.  
  340.   err = !err_string
  341.   syserr = !syserr_string
  342.   message, /NONAME, /CONTINUE, $
  343.       'XMANAGER: Caught unexpected error from client application. Message follows...'
  344.   printf, -2, !msg_prefix, err
  345.   if (strlen(syserr) gt 0) then printf, -2, !msg_prefix, syserr
  346.  
  347. END
  348.  
  349.  
  350.  
  351. PRO ValidateManagedWidgets
  352.   ; Makes sure all the widgets in the list of managed widgets are still
  353.   ; valid, and removes those that aren't.
  354.  
  355.   COMMON managed,    ids, $        ; IDs of widgets being managed
  356.               names, $    ; and their names
  357.             modalList    ; list of active modal widgets
  358.  
  359.   ; initialize the lists
  360.   IF (NOT keyword_set(ids)) THEN BEGIN
  361.     ids = 0L
  362.     names = 0
  363.   ENDIF
  364.   
  365.   ; if the list is empty, it's valid
  366.   IF (ids[0] EQ 0L) THEN RETURN
  367.  
  368.   ; which ones are valid?
  369.   valid = where(widget_info(ids, /managed))
  370.   
  371.   ; build new lists from those that were valid in the old lists
  372.   IF (valid[0] EQ -1) THEN BEGIN
  373.     ids = 0L
  374.     names = 0
  375.   ENDIF ELSE BEGIN
  376.     ids = ids[valid]
  377.     names = names[valid]
  378.   ENDELSE
  379.  
  380. END
  381.  
  382.  
  383.  
  384. PRO AddManagedWidget, name, id
  385.   ; Adds the given widget with its name to the list of managed widgets
  386.   ;
  387.   ; The list of managed widgets is kept as a convenience for applications
  388.   ; that want to register their functionality by name. For instance, an app
  389.   ; may not want to bring up a particular dialog if there is already one up.
  390.   ; They can find out if the dialog is running by calling the XREGISTERED
  391.   ; routine
  392.  
  393.   COMMON managed
  394.   
  395.   ValidateManagedWidgets
  396.   
  397.   IF (ids[0] EQ 0L) THEN BEGIN
  398.     ; create new lists
  399.     ids = [ id ]
  400.     names = [ name ]
  401.   ENDIF ELSE BEGIN
  402.     ; insert at the beginning of the lists
  403.     ids = [ id, ids ]
  404.     names = [ name, names ]
  405.   ENDELSE
  406.   
  407. END
  408.  
  409.  
  410.  
  411. FUNCTION LookupManagedWidget, name
  412.   ; Returns the widget id of the named widget, or 0L if not found
  413.  
  414.   COMMON managed
  415.   
  416.   ValidateManagedWidgets
  417.   
  418.   IF (ids[0] NE 0L) THEN BEGIN
  419.     found = where(names EQ name)
  420.     IF (found[0] NE -1) THEN BEGIN
  421.       RETURN, ids[found[0]]
  422.     ENDIF
  423.   ENDIF
  424.  
  425.   RETURN, 0L
  426. END
  427.  
  428.  
  429.  
  430. PRO XUNREGISTER, corpse
  431.   ; ------------------------------------------------------------------
  432.   ; | PLEASE NOTE: This routine is OBSOLETE. It's functionality is   |
  433.   ; | is no longer necessary.                                        |
  434.   ; ------------------------------------------------------------------
  435.   ;
  436.   ;    This procedure used to remove a dead widget from the Xmanagers common
  437.   ;    block, but that information is now maintained internally by IDL.
  438.  
  439.   COMMON XUNREGISTER_OBSOLETE, obsolete
  440.   
  441.   IF (NOT keyword_set(obsolete)) THEN BEGIN
  442.     obsolete = 1
  443.     message, /info, 'this routine is obsolete'
  444.   END
  445.   
  446.   ; Might as well validate the list now (even though it would happen later)
  447.   ValidateManagedWidgets
  448.  
  449. END
  450.  
  451.  
  452.  
  453.  
  454.  
  455. PRO XMANAGER_EVLOOP_STANDARD
  456.   ; This is the standard XMANAGER event loop. It works by dispatching
  457.   ; events for all managed widgets until there are none left that require
  458.   ; blocking. In the best case, the command line is able to dispatch events
  459.   ; and there are no clients that require blocking (specified via the
  460.   ; NO_BLOCK keyword to XMANAGER) and we are able to return immediately.
  461.  
  462.   COMMON xmanager_local, fake_modal_obsolete, xmanager_catch
  463.  
  464.  
  465.   ; WARNING: Undocumented feature. See RESTRICTIONS above for details.
  466.   active = widget_info(/XMANAGER_BLOCK)
  467.   WHILE (active NE 0) DO BEGIN
  468.     err = 0
  469.     IF (xmanager_catch) THEN catch, err
  470.     IF (err EQ 0) THEN BEGIN 
  471.       ; WARNING: Undocumented feature. See RESTRICTIONS above for details.
  472.       tmp = widget_event(/XMANAGER_BLOCK)
  473.     ENDIF ELSE XmanagerPrintError
  474.     IF (xmanager_catch) THEN catch, /cancel
  475.     ; WARNING: Undocumented feature. See RESTRICTIONS above for details.
  476.     active = widget_info(/XMANAGER_BLOCK)
  477.   ENDWHILE
  478.  
  479. END
  480.  
  481.  
  482.  
  483. PRO XMANAGER_EVLOOP_REAL_MODAL, modal_id
  484.   ; This version of the XMANAGER event loop is used when a client with
  485.   ; the MODAL keyword set on its TLB has been passed in. It dispatches
  486.   ; events for that client until it is done. Events for other clients
  487.   ; are also flushed at critical points so that expose events are not
  488.   ; delayed unnecessarily.
  489.  
  490.   COMMON xmanager_local
  491.  
  492.  
  493.   active = 1
  494.   WHILE (active NE 0) DO BEGIN
  495.     err = 0
  496.     IF (xmanager_catch) THEN catch, err
  497.       IF (err EQ 0) THEN BEGIN
  498.         ; WARNING: Undocumented feature. See RESTRICTIONS above for details.
  499.         tmp = widget_event(MODAL_ID, bad_id=bad, /BREAK_ON_EXPOSE)
  500.       ENDIF ELSE XmanagerPrintError
  501.       IF (xmanager_catch) THEN catch, /cancel
  502.       active = widget_info(MODAL_ID, /managed)
  503.  
  504.       ; Modal event handling returned. Flush events for other widgets
  505.       ; so we do not keep expose events (among others) blocked.
  506.       IF (active) THEN BEGIN
  507.         err = 0
  508.         IF (xmanager_catch) THEN catch, err
  509.         IF (err EQ 0) THEN BEGIN
  510.           tmp = widget_event(/NOWAIT)
  511.         ENDIF ELSE XmanagerPrintError
  512.         IF (xmanager_catch) THEN catch, /cancel
  513.       ENDIF
  514.   ENDWHILE
  515. END
  516.  
  517.  
  518.  
  519. PRO XMANAGER_EVLOOP_FAKE_MODAL, ID
  520.   ; This version of the XMANAGER event loop is used when a client is
  521.   ; registered with the MODAL keyword to XMANAGER. It fakes the appearance
  522.   ; of real modality by making the other existing clients insensitive while
  523.   ; the modal widget exists.
  524.  
  525.   COMMON managed
  526.   COMMON xmanager_local
  527.  
  528.  
  529.   ; Remember the current modal list so it can be restored afterwards
  530.   oldModalList = modalList
  531.   modalList = [ ID ]
  532.  
  533.   ; Get list of clients that should be desensitized to mimic modality.
  534.   ; If this is the outermost modal, then the list of all currently
  535.   ; managed widgets is used. If this is a nested inner modal, then
  536.   ; use the oldModalList.
  537.   IF (keyword_set(oldModalList)) THEN BEGIN
  538.     senslist = oldModalList
  539.   ENDIF ELSE BEGIN
  540.     WIDGET_CONTROL, ID, managed=0    ; So won't show up in following statement
  541.     senslist = WIDGET_INFO(/MANAGED)
  542.     WIDGET_CONTROL, ID, /MANAGED     ; Put it back
  543.   ENDELSE
  544.   for i = 0, n_elements(senslist) - 1 do $
  545.     WIDGET_CONTROL, BAD_ID=ignore_bad, senslist[i], SENSITIVE=0
  546.  
  547.  
  548.   ; Process events only for clients in the modal list. This list may gain
  549.   ; members if event processing leads to other applications being registered
  550.   ; via a recursive call to XMANAGER.
  551.   tmp = where(widget_info(modalList, /managed), active)
  552.   WHILE (active NE 0) DO BEGIN
  553.     err = 0
  554.     IF (xmanager_catch) THEN catch, err
  555.     tmp = modalList
  556.     IF (err EQ 0) THEN BEGIN
  557.       ; WARNING: Undocumented feature. See RESTRICTIONS above for details.
  558.       tmp = widget_event(tmp, bad_id=bad, /BREAK_ON_EXPOSE)
  559.     ENDIF ELSE XmanagerPrintError
  560.     IF (xmanager_catch) THEN catch, /cancel
  561.     tmp = where(widget_info(modalList, /managed), active)
  562.     IF (active NE 0) THEN modalList = modalList[tmp]
  563.     ;
  564.     ; Modal event handling returned, flush events for other widgets
  565.     ; if any so we do not keep expose events etc. blocked
  566.     ;
  567.     IF (active) THEN BEGIN
  568.       err = 0
  569.       IF (xmanager_catch) THEN catch, err
  570.       IF (err EQ 0) THEN BEGIN
  571.         tmp = widget_event(/NOWAIT)
  572.       ENDIF ELSE XmanagerPrintError
  573.       IF (xmanager_catch) THEN catch, /cancel
  574.     ENDIF
  575.   ENDWHILE
  576.  
  577.   for i = 0, n_elements(senslist) - 1 do $
  578.     WIDGET_CONTROL, BAD_ID=ignore_bad, senslist[i], /SENSITIVE
  579.  
  580.   ; restore the outer XMANAGER's list of modal widgets
  581.   modalList = oldModalList
  582.  
  583. END
  584.  
  585.  
  586.  
  587.  
  588.  
  589. PRO XMANAGER,    NAME, ID, BACKGROUND = background, CATCH = catch, $
  590.         CLEANUP = cleanup, EVENT_HANDLER = event_handler, $
  591.         GROUP_LEADER = group_leader, JUST_REG = just_reg, $
  592.         MODAL = modal, NO_BLOCK = no_block
  593.  
  594.   COMMON managed
  595.   COMMON xmanager_local
  596.  
  597.  
  598.   isFakeModal = keyword_set(modal)
  599.  
  600.   ; print out obsolete keyword messages
  601.   IF (keyword_set(background)) THEN BEGIN
  602.     message, "The BACKGROUND keyword to the XMANAGER procedure is " + $
  603.          "obsolete. It is superseded by the TIMER keyword to " + $
  604.          "the WIDGET_CONTROL procedure.", /info
  605.   ENDIF
  606.   IF (isFakeModal AND (NOT keyword_set(fake_modal_obsolete))) THEN BEGIN
  607.     fake_modal_obsolete = 1
  608.     message, "The MODAL keyword to the XMANAGER procedure is " + $
  609.          "obsolete. It is superseded by the MODAL keyword to " + $
  610.          "the WIDGET_BASE function.", /info
  611.   ENDIF
  612.  
  613.  
  614.   ; Initialization
  615.   if (n_elements(catch) ne 0) THEN BEGIN
  616.     xmanager_catch = catch ne 0
  617.     message, /INFO, 'Error handling is now ' + (['off', 'on'])[xmanager_catch]
  618.     return
  619.   ENDIF ELSE if (n_elements(xmanager_catch) EQ 0) then xmanager_catch = 1;
  620.   isRealModal = 0
  621.   if (N_ELEMENTS(just_reg) eq 0) then just_reg = 0
  622.   IF (isFakeModal) THEN just_reg = 0;
  623.   IF (NOT keyword_set(modalList)) THEN modalList = 0
  624.   ValidateManagedWidgets
  625.  
  626.  
  627.   ; Argument setup
  628.   if (N_PARAMS() EQ 0) THEN BEGIN
  629.     IF (ids[0] EQ 0L) THEN BEGIN
  630.       message, 'No widgets are currently being managed.', /info
  631.       RETURN
  632.     ENDIF
  633.   ENDIF ELSE IF (N_PARAMS() NE 2) THEN BEGIN
  634.     message, 'Wrong number of arguments, usage: XMANAGER [, name, id]'
  635.   ENDIF ELSE BEGIN    ;2 argument case
  636.  
  637.     ; Check the arguments
  638.     IF (NOT widget_info(id, /valid)) THEN message, 'Invalid widget ID.'
  639.     nameinfo = size(name)
  640.     IF ((nameinfo[0] NE 0) OR (nameinfo[1] NE 7)) THEN $
  641.       message, 'Invalid widget name.'
  642.  
  643.  
  644.     ; If TLB is modal, block in XMANAGER till you are done
  645.     IF (widget_info(id, /Modal)) THEN isRealModal = 1
  646.   
  647.     IF (keyword_set(cleanup)) THEN widget_control, id, kill_notify=cleanup
  648.     IF (NOT keyword_set(event_handler)) THEN event_handler = name + '_event'
  649.         
  650.     ; Register new widget
  651.     AddManagedWidget, name, id
  652.   
  653.     ; Mark the widget for event processing
  654.     widget_control, id, /managed, event_pro=event_handler
  655.  
  656.     ; Unless the caller set NO_BLOCK to indicate otherwise, mark
  657.     ; this client as requiring XMANAGER to block. This decision is driven
  658.     ; by backward compatibility concerns. During the IDL 5.0 beta we discovered
  659.     ; that many customers have code that depends on the blocking behavior.
  660.     ;
  661.     ; WARNING: Undocumented feature. See RESTRICTIONS above for details.
  662.     if keyword_set(no_block) then WIDGET_CONTROL, /XMANAGER_ACTIVE_COMMAND, id
  663.   
  664.     ; pass the group_leader keyword through
  665.     IF (keyword_set(group_leader)) THEN $
  666.       widget_control, id, group_leader=group_leader
  667.   
  668.  
  669.  
  670.     ; Modal Widget Registration
  671.     IF (keyword_set(modalList) and (not isFakeModal)) THEN BEGIN
  672.  
  673.       ; This client is a non-modal widget, being started while a
  674.       ; fake modal is already up. Just add the new widget to the modal
  675.       ; list and return immediately. The fake modal event loop will
  676.       ; dispatch its events as well as the modal clients.
  677.       modalList = [ modalList, ID ]
  678.       just_reg = 1    ; Don't process events. Instead, return immediately
  679.   
  680.       ; need to break out of the outer widget_event call so that the
  681.       ; outer xmanager can see that outmodal has changed
  682.       ; WARNING: Undocumented feature. See RESTRICTIONS above for details.
  683.       widget_control, /event_break
  684.       
  685.     ENDIF         ; modal
  686.  
  687.   ENDELSE        ; 2 argument case
  688.  
  689.  
  690.  
  691.   ; Event Processing.
  692.   IF (NOT just_reg) THEN BEGIN
  693.     IF (isRealModal) THEN BEGIN
  694.       XMANAGER_EVLOOP_REAL_MODAL, ID
  695.     ENDIF ELSE IF isFakeModal THEN BEGIN
  696.        XMANAGER_EVLOOP_FAKE_MODAL, ID
  697.     ENDIF ELSE BEGIN
  698.       XMANAGER_EVLOOP_STANDARD
  699.     ENDELSE
  700.  
  701.     ; keep our list clean and up to date
  702.     ValidateManagedWidgets
  703.       
  704.   ENDIF
  705.  
  706. END
  707.  
  708.